Repository Public
1import type { Metadata } from "next";2import { FilmGrid } from "@/components/FilmCard";3import { searchFilms } from "@/lib/films";4import { dict, href, type Locale } from "@/lib/i18n";56export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {7 const locale = (await params).locale as Locale;8 return { title: dict(locale).search.title, robots: { index: false }, alternates: { canonical: href(locale, "/search") } };9}1011export default async function Search({ params, searchParams }: { params: Promise<{ locale: string }>; searchParams: Promise<{ q?: string }> }) {12 const locale = (await params).locale as Locale;13 const q = ((await searchParams).q ?? "").slice(0, 120);14 const t = dict(locale);15 const hits = q ? await searchFilms(locale, q) : [];16 return (17 <div className="py-10">18 <h1 className="display text-5xl md:text-6xl">{t.search.title}</h1>19 <form action={href(locale, "/search")} role="search" className="mt-6 flex max-w-2xl gap-2">20 <label htmlFor="q" className="sr-only">{t.search.title}</label>21 <input id="q" name="q" type="search" defaultValue={q} placeholder={t.search.placeholder} className="field" autoComplete="off" maxLength={120} />22 <button type="submit" className="btn btn-primary">{t.search.button}</button>23 </form>24 <p className="mt-3 text-sm text-[var(--color-faint)]">{t.search.hint}</p>25 <div className="mt-8" aria-live="polite">26 {q && !hits.length && <p className="card p-8 text-[var(--color-muted)]">{t.search.none}</p>}27 {hits.length > 0 && <FilmGrid films={hits.map((h) => h.film)} locale={locale} notes={Object.fromEntries(hits.map((h) => [h.film.id, `${t.search.matched}: ${h.signals.join(", ")}`]))} />}28 </div>29 </div>30 );31}32